﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace THO7AlgoritmTimerApplication.Filters
{
    public class MedianFilter : Filter
    {
        public MedianFilter()
            : base()
        {
        }

        public override Bitmap RunFilter()
        {
            Bitmap output = new Bitmap(_width, _height);
            BitmapData outputData = output.LockBits(new Rectangle(0, 0, _width, _height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            int totalWidth = _width * 3;

            int srcOffset = _sourceData.Stride - totalWidth;
            int optOffset = outputData.Stride - totalWidth;

            int filterWidth = 3;
            int filterWidthHalf = filterWidth/2;

            byte[] byteToRemove = new byte[_height * _width * filterWidth];
            byte[] byteToAdd = new byte[_height * _width * filterWidth];

            SortArray ar = new SortArray();

            unsafe
            {
                byte* srcPnt = (byte*)_sourceData.Scan0;
                byte* optPnt = (byte*)outputData.Scan0;
                for (int y = 0; y < _height; y++)
                {
                    for (int x = 0; x < _width; x++)
                    {
                        if (y >= filterWidthHalf && y < (_height - filterWidthHalf) && x >= filterWidthHalf && x < (_width - filterWidthHalf))
                        {
                            byte[] remove = new byte[filterWidth];
                            byte[] add = new byte[filterWidth];
                            int cnt = 0;
                            for (int height = -filterWidthHalf; height < filterWidthHalf; height++)
                            {
                                //byteToRemove[(y * _width) + x] = srcPnt[(height * _width) + filterWidthHalf];
                                //byteToAdd[(y * _width) + x] = srcPnt[(height * _width) - filterWidthHalf];
                                // EASILY OPTIMIZABLE!!! -Change Pointer before For loop, reduces the amount of *!
                                remove[cnt] = srcPnt[(height * _width) + filterWidthHalf];
                                add[cnt] = srcPnt[(height * _width) - filterWidthHalf];
                                cnt++;

                            }
                            byte newB = ar.Replace(add, remove);
                            optPnt[0] = newB;
                            optPnt[1] = newB;
                            optPnt[2] = newB;
                        }
                        else
                        {
                            optPnt[0] = srcPnt[0];
                            optPnt[1] = srcPnt[1];
                            optPnt[2] = srcPnt[2];
                        }
                        srcPnt += 3;
                        optPnt += 3;
                    }

                    srcPnt += srcOffset;
                    optPnt += optOffset;
                }
            }
            output.UnlockBits(outputData);
            return output;
        }
    }
}
